﻿module poseidon.intellisense.autocomplete;

private
{
	import Analyzer.D.syntax.CoreAnalyzer;
	import poseidon.intellisense.search;
	import std.string;
	import poseidon.controller.gui;
	import poseidon.controller.packageexplorer;
}

const char[][] keywords_d = [ /*"Pascal", "Windows",*/ "abstract", "alias", "align", "asm", "assert", "auto", "body", "bool", "break", "byte",
							  "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class", "const", "continue",
							  "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated", "do", "double", 
							  "else", "enum", "export", "extern", "false", "final", "finally", "float", "for", "foreach", "function",
							  "goto", "idouble", "if", "ifloat", "import", "inout", "int", "interface", "invariant",
							  "ireal", "is", "lazy", "long", "mixin", "module", "new", "null",/*
							  "opAddAssign", "opAndAssign", "opApply", "opCall", "opCast", "opCatAssign", "opDivAssign",
							  "opIndex", "opIndexAssign", "opMulAssign", "opModAssign", "opOrAssign", "opPostInc",
							  "opPostDec", "opSubAssign", "opXorAssign", "opSlice", "opShlAssign", "opShrAssign", "opUShrAssign",*/
							  "out", "override", "package", "pragma", "private", "protected", "public",
							  "real", "ref", "return", "scope", "short", "static", "struct", "super", "switch", "synchronized",
							  "template", "this", "throw", "true", "try", "typedef", "typeid", "typeof",
							  "ubyte", "ucent", "uint", "ulong", "union", "unittest", "ushort",
							  "version", "void", "volatile", "wchar", "while", "with" ];


interface IComplete
{
	char[][] rootSearch( char[] root );
}

// KeywordComplete
class KeywordComplete:IComplete
{	
	char[][] rootSearch( char[] root )
	{
		char[][] results;
		if( root.length  ) char_rootSearchR( 0, keywords_d.length - 1, std.string.tolower( root ) , keywords_d, results  );

		return results;
	} 
}

// ImportComplete
class ImportComplete:IComplete
{
	char[][] dirs;
	char[][] baseDirs;

	void addDirs( char[] base, char[][] d )  
	{ 
		baseDirs ~= base;
		dirs ~= d; 
	}
  
	char[] _filterResults( char[][] results )
	{
		char[][] uniques;

		foreach( char[] r; results )
		{
		    if( std.path.getExt( r ) == "d" )
				uniques ~= r[0 .. $ - 2]; // 如果附屬檔名為d,取得名稱
			else
				if( r.find(".") == -1 ) uniques ~= r;
		}

		if( uniques.length )
			return std.string.join( uniques.sort, "?22 " ) ~ "?22";
		else
			return null;
	}

	char[] initialImports()
	{
		char[][] results;

		foreach( char[] dir; baseDirs )
			results ~= std.file.listdir( dir );

		return _filterResults(results);
	}

	char[] autoCSearch( char[] path )
	{
		return _filterResults( rootSearch( path ) );
	}

	char[][] rootSearch( char[] path ) 
	{
		char[][] results;

		foreach ( char[] dir; dirs )
		{
			if ( dir.length > path.length )
			{
	    	    if( dir[( dir.length - path.length )..$] == path )
				{
					results = std.file.listdir( dir ); // 此dir目錄中的所有檔案及子目錄--只有名稱及副檔名,無目錄
					break;
				}
			}
		}

		return results;
	}
}


// MRUComplete
class MRUComplete : IComplete
{
	private char[][] items;

	void addItem( char[] i )
	{ 
		i = i.strip();
		if ( ! TArray!(char[]).array_contains( items, i ) ) items ~= i; // make sure its unique
	} 

	char[][] rootSearch( char[] root )
	{
		char[][] results;
		if( root.length  ) char_rootSearchR( 0, items.length - 1, std.string.tolower( root ) , items, results );

		return results;
	}
}









// AutoComplete
class AutoComplete
{
	private import poseidon.globals;
	private import dwt.all;

	// 單獨檔案編輯時,其管理的projaect 為 +++SYSTEM_PROJECT+++ -> projectParsers[+++SYSTEM_PROJECT+++] 
	
	CAnalyzerTreeNode[char[]][char[]]	projectParsers;
	CAnalyzerTreeNode[char[]][char[]]	defaultParsers;
	
	CAnalyzerTreeNode	 				fileParser;
	//private char[]						fileParserPath;

	KeywordComplete 					keywordParser;
	MRUComplete 						mruParser;
	ImportComplete 						importParser;
  
	this()
	{
		keywordParser = new KeywordComplete;
		mruParser = new MRUComplete;
		importParser = new ImportComplete;
	}

	void setFileParser( CAnalyzerTreeNode f ){ fileParser = f; }
	
	//void setFileParserPath( char[] path ){ fileParserPath = path; }

	//char[] getFileParserPath(){ return fileParserPath;}

	CAnalyzerTreeNode getProjectParser( char[] fileName )
	{
		if( !projectParsers.length ) return null;

		char[] projectName = sGUI.packageExp.getActiveProjectName();

		if( projectName in projectParsers )
		{
			if( fileName in projectParsers[projectName] )
				return projectParsers[projectName][fileName];
			else
				return null;
		}
		else
			return null;
	}


	private void _message( Object args )
	{
		StringObj s = cast(StringObj) args;
		sGUI.outputPanel.appendString( s.data );
	}

	void addProjectParser( char[][] paths )
	{
		char[] projectName = sGUI.packageExp.getActiveProjectName();

		Display display = Display.getDefault();
		
		foreach( char[] s; paths )
		{
			if( !std.string.icmp( std.path.getExt( s ), "d" ) || !std.string.icmp( std.path.getExt( s ), "di" )  )
			{
				try
				{
					projectParsers[projectName][s] = Analyzer.D.syntax.CoreAnalyzer.parseFileHSU( s );
					if( Globals.backLoadParser )
						display.asyncExec( new StringObj( "File[ "~ s ~ " ] Parsed.\n" ) , &_message );
					else
						sGUI.outputPanel.appendString( "File[ "~ s ~ " ] Parsed.\n" );
				}
				catch( Exception e )
				{
					if( Globals.backLoadParser )
						display.asyncExec( new StringObj( "      File[ "~ s ~ " ] Parsed Error.\n" ) , &_message );
					else
					{
						sGUI.outputPanel.setForeColor( 0, 0, 0 );
						sGUI.outputPanel.appendString( "      File[ "~ s ~ " ] Parsed Error.\n" );
					}
				}
			}
		}

		if( Globals.parseAllModule ) setAdditionImportModules();
	}

	void refreshFileParser( char[][] paths )
	{
		char[] projectName = sGUI.packageExp.getActiveProjectName();

		if( projectName in projectParsers )
		{
			/+
			foreach( char[] key; projectParsers[projectName].keys )
			{
				if( key.length > 5 )
					if( key[0..5] == "<ana>" ) continue;
					
				bool bMatch;
				foreach( char[] fileName; paths )
				{
					if( key == fileName )
					{
						bMatch = true;
						break;
					}
				}

				if( !bMatch ) removeSingleFileParser( key, projectName );
			}
			+/

			foreach( char[] fileName; paths )
				if( !( fileName in projectParsers[projectName] ) ) addSingleFileParser( fileName, projectName );
		}
		else
			addProjectParser( paths );
	}
	

	void updateProjectParser( CAnalyzerTreeNode analyzer, char[] fileName )
	{
		char[] projectName = sGUI.packageExp.getActiveProjectName();

		if( projectName in projectParsers )
		{
			if( fileName in projectParsers[projectName] )
			{
				bool BReverseFileParse;
				
				CAnalyzerTreeNode parser = projectParsers[projectName][fileName];
				delete parser;

				if( analyzer !is null )
				{
					projectParsers[projectName][fileName] = analyzer;
					sGUI.outputPanel.setForeColor( 0, 0, 0 );
					sGUI.outputPanel.appendString( "Project[ " ~ projectName ~ " ][ "~ fileName ~ " ] Parser Updated.\n" );
				}
				else
				{
					projectParsers[projectName].remove( fileName );
				}
			}
			else
			{
				if( analyzer !is null )
				{
					projectParsers[projectName][fileName] = analyzer;
					sGUI.outputPanel.setForeColor( 0, 0, 0 );
					sGUI.outputPanel.appendString( "Project[ " ~ projectName ~ " ][ "~ fileName ~ " ] Parser Added.\n" );
				}
			}
		}
		else
		{
			if( analyzer )
			{
				projectParsers[projectName][fileName] = analyzer;
				sGUI.outputPanel.setForeColor( 0, 0, 0 );
				sGUI.outputPanel.appendString( "Project[ " ~ projectName ~ " ][ "~ fileName ~ " ] Parser Added.\n" );
			}
		}
	}

	bool addSingleFileParser( char[] fileName, char[] projectName )
	{
		if( projectName in projectParsers )
		{
			if( fileName in projectParsers[projectName] )
			{
				CAnalyzerTreeNode t = projectParsers[projectName][fileName];
				if( t ) delete t;
			}

			try
			{
				projectParsers[projectName][fileName] = Analyzer.D.syntax.CoreAnalyzer.parseFileHSU( fileName );
				sGUI.outputPanel.setForeColor( 0, 0, 0 );
				sGUI.outputPanel.appendString( "Project[ " ~ projectName ~ " ][ "~ fileName ~ " ] Parser Added.\n" );
				return true;
			}
			catch( Exception e )
			{
				if( fileName in projectParsers[projectName] ) projectParsers[projectName].remove( fileName );
				return false;
			}
		}
		
		return false;
	}
	

	bool removeSingleFileParser( char[] fileName, char[] projectName )
	{
		if( projectName in projectParsers )
		{
			if( fileName in projectParsers[projectName] )
			{
				CAnalyzerTreeNode t = projectParsers[projectName][fileName];
				if( t ) delete t;
				projectParsers[projectName].remove( fileName );
				sGUI.outputPanel.setForeColor( 0, 0, 0 );
				sGUI.outputPanel.appendString( "Removed File[ " ~ fileName ~ " ] Parser.\n" );				
				return true;
			}
		}
		return false;
	}

	bool renSingleFileParser( char[] fileName, char[] newFileName, char[] projectName )
	{
		if( projectName in projectParsers )
		{
			if( fileName in projectParsers[projectName] )
			{
				projectParsers[projectName][newFileName] = projectParsers[projectName][fileName].dup();
				projectParsers[projectName].remove( fileName );

				sGUI.outputPanel.appendString( "Rename File[ " ~ fileName ~ " ] To [ " ~ newFileName ~ " ].\n" );
				return true;
			}
		}
		return false;
	}

	
	void deleteProjectParser( char[] projectName )
	{
		if( projectName in projectParsers )
		{
			foreach( CAnalyzerTreeNode t; projectParsers[projectName] )
				if( t ) delete t;

			projectParsers.remove( projectName );
			sGUI.outputPanel.setForeColor( 0, 0, 0 );
			sGUI.outputPanel.appendString( "Removed project[ " ~ projectName ~ " ].\n" );
		}
	}


	void loadDefaultParser( char[] dir )
	{
		try
		{
			CFindAllFile stdFiles = new CFindAllFile( dir );

			char[][] 	files = stdFiles.getFiles();
			char[]		defaultParserName = std.string.tolower( std.path.getBaseName( dir ) );

			sGUI.outputPanel.appendLine( "Default Paser[ " ~ defaultParserName ~ " ] Loading......" );
			sGUI.outputPanel.setForeColor( 0, 160, 0 );

			foreach( char[] s; files )
			{
				if( std.path.getExt( s ) == "ana" )
				{
					CAnalyzerTreeNode tempAnalyzer = Analyzer.D.syntax.nodeHsu.loadAnalyzerNode( s );
					if( tempAnalyzer )
					{
						char[] moduleName = tempAnalyzer.getLeaf( 0 ).identifier;
								
						defaultParsers[defaultParserName][moduleName] = tempAnalyzer;
						sGUI.outputPanel.appendLine( "[ " ~ moduleName ~ " ] " ~ "Loaded." );
					}
					else
					{
						sGUI.outputPanel.appendLine( "   The .ana File[ " ~ s ~ " ] may be broken" );
					}
				}
			}
			sGUI.outputPanel.appendLine( "......Load Finish.\n" );
		}
		catch( Exception e )
		{
			char[]	defaultParserName = std.string.tolower( std.path.getBaseName( dir ) );
			sGUI.outputPanel.appendLine(dir);
			sGUI.outputPanel.appendLine( "   Default Parser [ " ~  defaultParserName ~ " ] Load Error. ( Wrong Parser Path )" );
			// MessageBox.showMessage( e.toString );
			// throw new Exception( "Load Default Parser Error!" );
		}
	}
	
	char[] forceComplete( char[] word )
	{
		/*
		char[][] words;

		words = mruParser.rootSearch( word );
		words ~= keywordParser.rootSearch( word );
     
		// 列出所有的 CAnalyzerTreeNode
		CAnalyzerTreeNode[] treeNodes = search( word, D_ALL );

		foreach( CAnalyzerTreeNode t; treeNodes )
			word ~= t.identifier;

		// 排列所有的words
		TArray!(char[]).sort( words, &icharCompare );
		char[][] uniques = TArray!(char[]).array_unique( words );
		char[] ret = std.string.join( uniques, " " );
			
		return ret;
		*/return null;
	}

	char[][] setMemberImage( CAnalyzerTreeNode[] nodes )
	{
		if( !nodes.length ) return null;
		
		char[][] words;
		
		foreach( CAnalyzerTreeNode t; nodes )
		{
			int m, v;

			switch( t.DType )
			{
				case D_FUNCTION: 	m = 0; break;
				case D_VARIABLE: 	m = 1; break;
				case D_CLASS: 		m = 2; break;
				case D_STRUCT: 		m = 3; break;
				case D_INTERFACE:	m = 4; break;
				case D_UNION:		m = 5; break;
				case D_ENUM:		m = 6; break;
				case D_PARAMETER:
					words ~= ( t.identifier ~ "?24" );
					continue;
					break;
				/+
				case D_ENUMMEMBER:
					words ~= ( t.identifier ~ "?25" );
					continue;
					break;
				+/
				case D_TEMPLATE:
					words ~= ( t.identifier ~ "?26" );
					continue;
					break;

				case D_IMPORT:
					if( t.typeIdentifier.length )
						words ~= ( t.typeIdentifier ~ "?22" );
					else
					{
						int dotPos = std.string.find( t.identifier, "." );
						if( dotPos < 0 ) dotPos = t.identifier.length;
							
						words ~= ( t.identifier[0..dotPos] ~ "?22" );
					}
					continue;
					break;

				default:
					words ~= ( t.identifier ~ "?23" );
					continue;
					break;
			}

			if( t.prot & D_Private ) 
				v = 0;
			else if( t.prot & D_Protected ) 
				v = 1;
			else
				v = 2;

			words ~= ( t.identifier ~ "?" ~ std.string.toString( m * 3 + v ) );
		}

		if( !words.length ) return null;

		scope CCharsSort!( char[] ) sortList = new CCharsSort!( char[] )( words );
		words = sortList.pop();

		char[]		prevWord = words[0];
		char[][] 	newWords;
		newWords ~= words[0];

		for( int i = 1; i < words.length; ++ i )
		{
			if( words[i] != prevWord )
			{
				prevWord = words[i];
				newWords ~= words[i];
			}
		}		

		return newWords;
	}


	char[] autoCSearch( char[] word, CAnalyzerTreeNode headNode )
	{
		char[][] 	words;
		char[] 		ret;

		words = mruParser.rootSearch( word );
		words ~= keywordParser.rootSearch( word );

		if( words.length )
		{
			TArray!(char[]).sort( words, &icharCompare );
			char[][] uniques = TArray!(char[]).array_unique( words );
			ret = std.string.join( uniques, "?21 " ) ~ "?21";
		}
			

		if( fileParser )
		{
			char[][] treeWords;
			
			CAnalyzerTreeNode[] treeNodesSum;
				
			if( !headNode )
				treeNodesSum = getAnalyzerAllNode( fileParser, D_ALL - D_MODULE - D_BLOCK );
			else
			{
				treeNodesSum = getAnalyzerAllNodeR( headNode, D_ALL - D_MODULE - D_BLOCK );
					
				CAnalyzerTreeNode[] 		importModules;		
				//if( getImport( "dummy", D_ALL, headNode, importModules, true ) !is null )
				//{
					getImport( "dummy", D_ALL, headNode, importModules, true );
					int DType = D_UDTS | D_FUNCTION | D_ALIAS | D_TYPEDEF | D_VARIABLE | D_IMPORT;
					foreach( CAnalyzerTreeNode a; importModules )
					{
						foreach( CAnalyzerTreeNode t; a.getAllLeaf() )
						{
							if( !( t.prot & D_Private ) && !( t.prot & D_Protected ) )
								if( t.DType & DType ) treeNodesSum ~= t;
						}
					}
				//}
			}

			if( treeNodesSum.length )
			{
				CAnalyzerTreeNode[] treeNodes = rootSearch( word, treeNodesSum );
				treeWords = setMemberImage( treeNodes );
				
				if( treeWords.length )
				{
					if( words.length ) 
						ret = ret ~ " " ~ std.string.join( treeWords, " " );
					else
						ret = std.string.join( treeWords, " " );
				}
			}
		}

		return ret;
	}	
	/+
	char[] autoCSearch( char[] word, CAnalyzerTreeNode headNode )
	{
		char[][] 	words;

		words = mruParser.rootSearch( word );
		words ~= keywordParser.rootSearch( word );

		if( !words.length ) // if no keywords or MRU
		{
			if( fileParser )
			{
				CAnalyzerTreeNode[] treeNodesSum;
				
				if( !headNode )
					treeNodesSum = getAnalyzerAllNode( fileParser, D_ALL - D_MODULE - D_BLOCK );
				else
				{
					treeNodesSum = getAnalyzerAllNodeR( headNode, D_ALL - D_MODULE - D_BLOCK );
					
					CAnalyzerTreeNode[] 		importModules;		
					getImport( "dummy", D_ALL, headNode, importModules, true );

					int DType = D_UDTS | D_FUNCTION | D_ALIAS | D_TYPEDEF | D_VARIABLE | D_IMPORT;
					foreach( CAnalyzerTreeNode a; importModules )
					{
						foreach( CAnalyzerTreeNode t; a.getAllLeaf() )
						{
							if( !( t.prot & D_Private ) && !( t.prot & D_Protected ) )
								if( t.DType & DType ) treeNodesSum ~= t;
						}
					}
				}

				if( !treeNodesSum.length ) return null;

				CAnalyzerTreeNode[] treeNodes = rootSearch( word, treeNodesSum );
				words = setMemberImage( treeNodes );
				
				if( !words.length ) return null;
				
				return std.string.join( words, " " );
			}

			return null;
		}
		
		if( !words.length ) return null;
		TArray!(char[]).sort( words, &icharCompare );
		char[][] uniques = TArray!(char[]).array_unique( words );
		char[] ret = std.string.join( uniques, "?21 " ) ~ "?21";

		return ret;
	}
	+/


	// 找出特定種類的 CAnalyzerTreeNode ( CAnalyzerTreeNode.name = ... )
	CAnalyzerTreeNode[] search( char[] word, int typeFlag = D_ALL, bool bPassFilePaser = false )
	{
		CAnalyzerTreeNode[] treeNodes;

		if( !fileParser ) return null;

		if( word.length )
		{
			if( !bPassFilePaser )
				if( !treeNodes.length ) treeNodes ~= lookAnalyzerTree( word, typeFlag, fileParser ); 
			
			if( !treeNodes.length ) // 再找專案的Parser
			{
				char[] projectName = sGUI.packageExp.getActiveProjectName();
				foreach ( CAnalyzerTreeNode p; projectParsers[projectName] )
					if( p != fileParser ) treeNodes ~= lookAnalyzerTree( word, typeFlag, p );
			}
			
		}

		return treeNodes;
	}		
		

	// 從根節點->子節點方向找尋及傳回所有適合的 CAnalyzerTreeNode
	CAnalyzerTreeNode[] lookAnalyzerTree( char[] ident, int typeFlag = D_ALL, CAnalyzerTreeNode activeTreeNode = null )
	{
		if( !ident.length ) return null;
		if( !activeTreeNode ) return null;

		CAnalyzerTreeNode[] analyzerTreeNodes;

		// Nested Function
		void _lookingFormHead( CAnalyzerTreeNode treeNode )
		{
			if( treeNode.DType & typeFlag  )
				if( treeNode.identifier == ident ) analyzerTreeNodes ~= treeNode;
			
			foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
				_lookingFormHead( t );
		}

		_lookingFormHead( activeTreeNode );

		return analyzerTreeNodes;
	}


	// 反向找尋及傳回第一個適合的 CAnalyzerTreeNode
	CAnalyzerTreeNode getAnalyzerTreeNode( char[] ident, int typeFlag = D_ALL, CAnalyzerTreeNode activeTreeNode = null,
					  bool bBottomLook = false )
	{
		if( !ident.length ) return null;
		if( !activeTreeNode ) return null;

		CAnalyzerTreeNode analyzerTreeNode;

		if( bBottomLook ) // 找尋此節點的葉節點
		{
			foreach( CAnalyzerTreeNode t; activeTreeNode.getAllLeaf() )
			{
				if( t.DType & typeFlag )
					if( t.identifier == ident )	return t;
			}
		}

		// Nested Function
		void _lookingFormNode( CAnalyzerTreeNode treeNode )
		{
			if( analyzerTreeNode ) return;
			
			CAnalyzerTreeNode rootNode = treeNode.getRoot();
			
			if( rootNode )
			{
				_lookingFormNode( rootNode );
				
				foreach( CAnalyzerTreeNode t; rootNode.getAllLeaf() )
				{
					if( t.DType & typeFlag )
					{
						if( t.identifier == ident )
						{
							analyzerTreeNode = t;
							break;
						}
					}
				}
			}
		}
		
		_lookingFormNode( activeTreeNode );

		return analyzerTreeNode;
	}
	

	// 找出繼承的類別們
	CAnalyzerTreeNode[] getBaseClassNode( CAnalyzerTreeNode treeNode  )
	{
		CAnalyzerTreeNode[] baseClassNodes;

		void _getNode( CAnalyzerTreeNode node )
		{
			if( !node.baseClass.length ) return;
			
			char[][] 			className = std.string.split( treeNode.baseClass, "," );
			CAnalyzerTreeNode[] nestClasses;


			foreach( char[] s; className )
			{
				int			DType = D_CLASS | D_INTERFACE;
				char[][] 	templateClassName = std.string.split( s, "!" );

				s = templateClassName[0];
				if( templateClassName.length > 1 ) DType = DType | D_TEMPLATE;

				
				// 先找原class所在Parser
				CAnalyzerTreeNode activeTreeNode = getAnalyzerTreeNode( s, DType, node, true );

				if( !activeTreeNode )
				{
					CAnalyzerTreeNode[] dummyAnalyzers;
					activeTreeNode = getImport( s, DType, node, dummyAnalyzers );

					if( activeTreeNode ) 
					{
						if( DType & D_TEMPLATE )
						{
							foreach( CAnalyzerTreeNode t; activeTreeNode.getAllLeaf() )
							{
								if( t.DType == D_CLASS || t.DType == D_INTERFACE )
									if( t.identifier == s )	
										activeTreeNode = t;
							}
						}
						baseClassNodes ~= activeTreeNode;
						nestClasses ~= activeTreeNode;
					}
				}else
				{
					if( DType & D_TEMPLATE )
					{
						foreach( CAnalyzerTreeNode t; activeTreeNode.getAllLeaf() )
						{
							if( t.DType == D_CLASS || t.DType == D_INTERFACE )
								if( t.identifier == s )	
									activeTreeNode = t;
						}
					}
					baseClassNodes ~= activeTreeNode;
				}
			}

			foreach( CAnalyzerTreeNode t; nestClasses )
			{
				if( t.DType & D_INTERFACE )	_getNode( t );
			}
				
		}

		_getNode( treeNode );

		return baseClassNodes;
	}
	
	// 取得
	CAnalyzerTreeNode getMemberAnalyzerTreeNode( char[] ident, int typeFlag = D_ALL, CAnalyzerTreeNode activeTreeNode = null, inout CAnalyzerTreeNode[] baseClasses = null )
	{
		if( !ident.length ) return null;
		if( !activeTreeNode ) return null;

		foreach( CAnalyzerTreeNode t; activeTreeNode.getAllLeaf() )
		{
			version( Windows )
			{
				if( t.DType & D_VERSION )
				{
					if( t.identifier == "Windows" || t.identifier == "Win32" )
					{
						CAnalyzerTreeNode versionNodeResult = getMemberAnalyzerTreeNode( ident, typeFlag, t, baseClasses );
						if( versionNodeResult ) return versionNodeResult;
					}
					continue;
				}
			}
			
			if( t.DType & typeFlag )
				if( t.identifier == ident )	return t;
		}

		// 找不到時找繼承父類別的成員
		if( activeTreeNode.baseClass.length )
		{
			baseClasses = getBaseClassNode( activeTreeNode );
			
			foreach( CAnalyzerTreeNode t; baseClasses )
			{
				foreach( CAnalyzerTreeNode tt; t.getAllLeaf() )
				{
					if( tt.DType & typeFlag )
						if( tt.identifier == ident )
							return tt;
				}
			}
		}

		return null;
	}


	CAnalyzerTreeNode[] getAnalyzerAllNode( CAnalyzerTreeNode node, int DType = D_ALL )
	{
		CAnalyzerTreeNode[] result;

		if( node.DType & D_MAINROOT )
		{
			void _getLeaf( CAnalyzerTreeNode _node )
			{
				if( _node.DType & DType )
				{
					result ~= _node;
					foreach( CAnalyzerTreeNode t; _node.getAllLeaf() ) _getLeaf( t );
				}
			}

			_getLeaf( node );

			return result;
		}

		return null;
	}

	CAnalyzerTreeNode[] getAnalyzerAllNodeR( CAnalyzerTreeNode node, int DType = D_ALL )
	{
		if( !node ) return null;

		CAnalyzerTreeNode[] results;

		// Nested Function
		void _lookingFormNode( CAnalyzerTreeNode treeNode )
		{
			if( treeNode )
			{
				foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
					if( t.DType & DType ) results ~= t;

				_lookingFormNode( treeNode.getRoot() );
			}
		}
		
		_lookingFormNode( node );

		return results;
	}
	

	// 取得目前專案中額外引含的模組
	void setAdditionImportModules( CAnalyzerTreeNode singleModule = null )
	{
		int[char[]] 	importedModuleNameArray;
		bool bFirstImport = true;


		char[] projectName = sGUI.packageExp.getActiveProjectName();

		Display display = Display.getDefault();

		if( singleModule is null )
		{
			if( Globals.backLoadParser )
				display.asyncExec( new StringObj( "\nAddition Parser Load......\n" ) , &_message );
			else
				sGUI.outputPanel.appendString( "\nAddition Parser Load......\n" );
		}
		else
		{
			if( Globals.backLoadParser )
				display.asyncExec( new StringObj( "" ) , &_message );
			else
				sGUI.outputPanel.appendLine( "" );
		}

		void _addParser( CAnalyzerTreeNode[] parsers )
		{
			if( !parsers.length ) return;
			
			CAnalyzerTreeNode[] addAnalyzers;
			char[][]			addImportNames;
			
			foreach( CAnalyzerTreeNode parser; parsers )
			{
				CAnalyzerTreeNode[] analyzerTreeNodes;
				
				foreach( CAnalyzerTreeNode t; getAnalyzerAllNode( parser ) )
					if( t.DType & D_IMPORT ) 
					{
						if( bFirstImport )
							analyzerTreeNodes ~= t;
						else
						{
							if( t.prot & D_Public ) analyzerTreeNodes ~= t;
						}
					}

				foreach( CAnalyzerTreeNode t; analyzerTreeNodes )
				{
					if( !( t.identifier in importedModuleNameArray ) )
					{
						addImportNames ~= t.identifier;
						importedModuleNameArray[t.identifier] = 1;
					}
				}
			}

			int countAddImportModule = addImportNames.length;
			if( countAddImportModule == 0 ) return;
			int count;

			foreach( char[] moduleName; addImportNames )
			{
				bool 		bGetDefaultparser;
				char[][] 	splitModuleName = std.string.split( moduleName, "." );
				char[] 		anaModuleName, defaultParserName, defaultParserFileName;
				
				if( splitModuleName.length > 1 )
				{
					defaultParserName = Globals.poseidonPath ~ "\\ana\\" ~ splitModuleName[0];
					if( std.file.exists( defaultParserName ) )
					{
						for( int i = 1; i < splitModuleName.length; ++ i )
							anaModuleName ~= ( "-" ~ splitModuleName[i] );

						anaModuleName = anaModuleName[1..length];
						defaultParserFileName = defaultParserName ~ "\\" ~ anaModuleName ~ ".ana";
						if( std.file.exists( defaultParserFileName ) )
						{
							try
							{
								CAnalyzerTreeNode defaultParserNode = loadAnalyzerNode( defaultParserFileName );
								char[] mName, fName;
								getModuleNames( defaultParserNode, mName, fName );
								projectParsers[projectName][fName] = defaultParserNode;
								addAnalyzers ~= defaultParserNode;

								if( Globals.backLoadParser )
									display.asyncExec( new StringObj( "Module[ "~ moduleName ~ " ] Loaded And Parsed.\n" ) , &_message );
								else
									sGUI.outputPanel.appendString( "Module[ "~ moduleName ~ " ] Loaded And Parsed.\n" );
									
								bGetDefaultparser = true;
								count ++;
								if( count >= countAddImportModule ) break;
							}
							catch( Exception e )
							{
								if( Globals.backLoadParser )
									display.asyncExec( new StringObj( "      Module[ "~ moduleName ~ " ] Parsed Error.\n" ) , &_message );
								else
									sGUI.outputPanel.appendString( "      Module[ "~ moduleName ~ " ] Parsed Error.\n" );
							}
						}
					}
				}

				if( !bGetDefaultparser )
				{
					foreach( char[] path; sGUI.packageExp.activeProject().projectIncludePaths ~ Globals.scINIImportPath )
					{
						char[] name = std.string.replace( moduleName, ".", "\\" );
						name = std.path.join( path, name );// ~".d";
					
						try
						{
							CAnalyzerTreeNode extraParser = Analyzer.D.syntax.CoreAnalyzer.parseFileHSU( name ~ ".di" );
							projectParsers[projectName][name ~ ".di"] = extraParser;
							addAnalyzers ~= extraParser;

							if( Globals.backLoadParser )
								display.asyncExec( new StringObj( "File[ "~ name ~ ".di ] Loaded And Parsed.\n" ) , &_message );
							else
								sGUI.outputPanel.appendString( "File[ "~ name ~ ".di ] Loaded And Parsed.\n" );
								
							count ++;
							if( count >= countAddImportModule ) break;
						}
						catch( Exception e )
						{
							try
							{
								CAnalyzerTreeNode extraParser = Analyzer.D.syntax.CoreAnalyzer.parseFileHSU( name ~ ".d" );
								projectParsers[projectName][name ~ ".d"] = extraParser;
								addAnalyzers ~= extraParser;

								if( Globals.backLoadParser )
									display.asyncExec( new StringObj( "File[ "~ name ~ ".d ] Loaded And Parsed.\n" ) , &_message );
								else
									sGUI.outputPanel.appendString( "File[ "~ name ~ ".d ] Loaded And Parsed.\n" );
									
								count ++;
								if( count >= countAddImportModule ) break;
							}
							catch( Exception e )
							{
								if( e.toString != "NoExist" )
								{
									if( Globals.backLoadParser )
										display.asyncExec( new StringObj( "      File[ "~ name ~ " ] Parsed Error.\n" ) , &_message );
									else
										sGUI.outputPanel.appendString( "      File[ "~ name ~ " ] Parsed Error.\n" );
								}
							}
						}
					}
					
					if( count >= countAddImportModule ) break;
				}
			}

			bFirstImport = false;
			_addParser( addAnalyzers );
		}
		

		CAnalyzerTreeNode[] parserGroup;
		
		foreach( CAnalyzerTreeNode t; projectParsers[projectName] )
		{
			if( t !is null )
			{
				char[] mName, mFullPath;
				getModuleNames( t, mName, mFullPath );			
				importedModuleNameArray[mName] = 1;
				if( singleModule is null ) parserGroup ~= t;
			}
		}

		if( singleModule !is null ) parserGroup ~= singleModule;
		
		_addParser( parserGroup );

		if( singleModule is null )
		{
			if( Globals.backLoadParser )
				display.asyncExec( new StringObj( "All Done.\n" ) , &_message );
			else
				sGUI.outputPanel.appendString( "All Done.\n" );
		}
	}	


	public void getModuleNames( CAnalyzerTreeNode node, inout char[] _moduleName, inout char[] _moduleFullPath )
	{
		while( !( node.DType & D_MAINROOT ) )
			node = node.getRoot();

		
		foreach( CAnalyzerTreeNode t; node.getAllLeaf() )
		{
			if( t.DType & D_MODULE )
			{
				_moduleName = t.identifier;
				_moduleFullPath = t.typeIdentifier;
				return;
			}
		}
	}
	

	CAnalyzerTreeNode getImport( char[] word, int typeFlag, CAnalyzerTreeNode activeTreeNode, out CAnalyzerTreeNode[] importedModules, bool bGetModules = false )
	{
		bool 				bInRootModule = true;
		int[char[]]			importedModuleNameArray;
		CAnalyzerTreeNode[]	importModules;
		//char[][] 			modulesName;
		CAnalyzerTreeNode	ret;
		CAnalyzerTreeNode	activeParser;


		char[] projectName = sGUI.packageExp.getActiveProjectName();


		char[] mName, mFullPath;

		if( activeTreeNode ) getModuleNames( activeTreeNode, mName, mFullPath );
		
		if( !activeTreeNode )
			activeParser = fileParser;
		else
			activeParser = getProjectParser( mFullPath );

		if( !activeParser || !word.length ) return null;

		importedModuleNameArray[mName] = 1;

		// Nested Function
		bool _inProjectParser( char[] m )
		{
			foreach( CAnalyzerTreeNode[char[]] t; defaultParsers )
				if( m in t ) return true;
			
			foreach( CAnalyzerTreeNode t; projectParsers[projectName] )
			{
				if( t !is null )
				{
					char[] name, fullPath;

					getModuleNames( t, name, fullPath );
					if( name == m ) return true;
				}
			}

			return false;
		}

		CAnalyzerTreeNode _getProjectParserByModuleName( char[] m )
		{
			foreach( CAnalyzerTreeNode[char[]] t; defaultParsers )
				if( m in t ) return t[m];			
			//if( m in defaultParsers["std"] ) return defaultParsers["std"][m];

			foreach( CAnalyzerTreeNode t; projectParsers[projectName] )
			{
				if( t !is null )
				{
					char[] name, fullPath;

					getModuleNames( t, name, fullPath );
					if( name == m ) return projectParsers[projectName][fullPath];
				}
			}

			return null;
		}

		
		// Nested Function
		void _lookingFormHead( CAnalyzerTreeNode treeNode )
		{
			if( ret ) return;

			while( !( treeNode.DType & D_MAINROOT ) ) treeNode = treeNode.getRoot();
			
			foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
			{
				if( !( t.prot & ( D_Private | D_Protected ) ) )
				{
					if( t.DType & typeFlag  )
					{
						if( t.identifier == word ) 
						{
							ret = t;
							return;
						}
					}
				}
			}
		}
		

		// 反向找尋及傳回適合的 D_IMPORT CAnalyzerTreeNode
		CAnalyzerTreeNode[] _getFirstImportNodes()
		{
			CAnalyzerTreeNode[] analyzerTreeNodes;

			if( !activeTreeNode ) return null;

			foreach( CAnalyzerTreeNode t; activeTreeNode.getAllLeaf() )
				if( t.DType & D_IMPORT ) analyzerTreeNodes ~= t;


			// Nested Function
			void _lookingFormNode( CAnalyzerTreeNode treeNode )
			{
				CAnalyzerTreeNode rootNode = treeNode.getRoot();
				
				if( rootNode )
				{
					foreach( CAnalyzerTreeNode t; rootNode.getAllLeaf() )
					{
						if( t.DType & D_IMPORT ) analyzerTreeNodes ~= t;
					}

					_lookingFormNode( rootNode );						
				}
			}
			
			_lookingFormNode( activeTreeNode );

			return analyzerTreeNodes;
		}
		
		void _findImport( CAnalyzerTreeNode analyzer )
		{
			char[][] insidemodulesName;

			if( analyzer )
			{
				if( bInRootModule ) // 第一次找尋import
				{
					CAnalyzerTreeNode[] importFirst = _getFirstImportNodes();
					foreach( CAnalyzerTreeNode t; importFirst )
					{
						if( !( t.identifier in importedModuleNameArray ) )
						{
							if( _inProjectParser( t.identifier ) )
							{
								insidemodulesName ~= t.identifier;
								importedModuleNameArray[t.identifier] = 1;
							}
						}
					}						
				}
				else
				{
					foreach( CAnalyzerTreeNode t; analyzer.getAllLeaf() )
					{
						if( t.DType & D_IMPORT )
						{
							if( !( t.identifier in importedModuleNameArray ) )
							{
								if( t.prot & D_Public )
								{
									if( _inProjectParser( t.identifier ) )
									{									
										insidemodulesName ~= t.identifier;
										importedModuleNameArray[t.identifier] = 1;
									}
								}
							}
						}
					}
				}
			}else
				return;

			bInRootModule = false;
			if( insidemodulesName.length )
			{
				//modulesName.length = 0;
				//modulesName ~= insidemodulesName;
				foreach( char[]	s; insidemodulesName )
				{
					CAnalyzerTreeNode a = _getProjectParserByModuleName( s );
					if( a ) 
					{
						importModules ~= a;
						_findImport( a );
					}
				}
			}
		}
	
		_findImport( activeParser );

		if( bGetModules )
		{
			//sGUI.outputPanel.appendString( "modules.length = " ~ std.string.toString( importModules.length ) ~ "\n" );
			/+
			foreach( CAnalyzerTreeNode a; importModules )
			{
				foreach( CAnalyzerTreeNode t; a.getAllLeaf() )
				{
					if( t.DType & D_MODULE )
					{
						sGUI.outputPanel.appendString( "modules.name = " ~ t.identifier ~ "\n" );
						break;
					}
				}
					
				//sGUI.outputPanel.appendString( "modules.name = " ~ a.identifier ~ "\n" );
			}
			+/
					
			importedModules = importModules;
			return null;
		}

		foreach( CAnalyzerTreeNode a; importModules )
		{
			//sGUI.outputPanel.appendString( "modules.name = " ~ a.identifier ~ "\n" );
			_lookingFormHead( a );
			if( ret ) break;
		}

		return ret;
	}


    private CAnalyzerTreeNode[] rootSearch( char[] root, CAnalyzerTreeNode[] allListings, int typeFlag = D_ALL )
	{
		CAnalyzerTreeNode[] matches;
		root = std.string.tolower( root );
		//typeFlag = typeFlag - D_IMPORT;
		foreach( CAnalyzerTreeNode t; allListings )
		{
			
			if( t.DType & D_IMPORT )
			{
				if( t.typeIdentifier.length )
				{
					if( t.typeIdentifier.length >= root.length )
						if( root == std.string.tolower( t.typeIdentifier[0..root.length] ) ) matches ~= t;

					continue;
				}
			}

			if( t.DType & typeFlag )
				if( t.identifier.length )
					if( t.identifier.length >= root.length ) 
						if( root == std.string.tolower( t.identifier[0..root.length] ) ) matches ~= t;
		}

		return matches;
    }
}
